package com.cdy.client;

import com.cdy.client.netty.NettyClient;
import com.cdy.common.command.RequestUploadCommand;
import com.cdy.common.command.UploadCommand;
import com.cdy.common.property.CommonProperty;
import com.cdy.common.response.RequestUploadResponse;
import com.cdy.common.response.Response;
import com.cdy.common.uitl.FileUtil;
import io.netty.buffer.ByteBuf;
import org.apache.commons.codec.digest.DigestUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import static com.cdy.common.property.CommonProperty.SmallSectionLength;

/**
 * 文件客户端
 * Created by 陈东一
 * 2019/10/19 0019 17:04
 */
public class FileUploadClient {
    
    public static BlockingQueue<UploadCommand> queue = new ArrayBlockingQueue<>(1000);
    public static volatile Boolean isFinish = false;
    public static File file;
    public static String md5;
    public static FileChannel channel;
    
    public static void main(String[] args) throws Exception {
        System.setProperty("io.netty.buffer.checkBounds", "false");
        file = new File("d:"+File.separator+"ArrayDemo.class");
        FileInputStream data = new FileInputStream(file);
        md5 = DigestUtils.md5Hex(data);
        data.close();
        channel = new RandomAccessFile(file, "r").getChannel();
        CommonProperty commonProperty = new CommonProperty();
        NettyClient nettyClient = new NettyClient(commonProperty);
        nettyClient.connect("127.0.0.1", 12345);
        
        while (true) {
            RequestUploadCommand requestCommand = new RequestUploadCommand();
            requestCommand.setFileLength(file.length());
            requestCommand.setFileName(file.getName());
            requestCommand.setFileMD5(md5);
            requestCommand.setClientId(commonProperty.getClientId());
            @SuppressWarnings("unchecked")
            Future<Response> send = (Future<Response>) nettyClient.send(requestCommand).orElseThrow(RuntimeException::new);
            Response response = send.get();
            RequestUploadResponse requestResponse = (RequestUploadResponse) response;
            if (requestResponse.getComplete()) {
                break;
            } else {
                for (int i = requestResponse.getBitBegin(); i < requestResponse.getBitSize(); i++) {
                    UploadCommand uploadCommand = initUploadCommand(commonProperty, requestResponse, i);
                    queue.add(uploadCommand);
                }
                while (!isFinish) {
                    UploadCommand poll = queue.poll(60, TimeUnit.SECONDS);
                    if (poll !=null) {
                        nettyClient.send(poll);
                    } else {
                        Thread.sleep(1000L);
                    }
                }
                break;
            }
        }
        nettyClient.close();
        channel.close();
        System.exit(0);

    }

    public static UploadCommand initUploadCommand(CommonProperty commonProperty, RequestUploadResponse requestResponse, int i) throws Exception {
        UploadCommand uploadCommand = new UploadCommand();
        uploadCommand.setBegin(requestResponse.getBegin() + i * SmallSectionLength);
        uploadCommand.setClientId(commonProperty.getClientId());
        uploadCommand.setSectionId(requestResponse.getSectionId());
        uploadCommand.setFileMD5(md5);
        uploadCommand.setSectionBegin(requestResponse.getBegin());
        uploadCommand.setBitBegin(requestResponse.getBitBegin());
        uploadCommand.setBitSize(requestResponse.getBitSize());
        uploadCommand.setBitTotal(requestResponse.getBitTotal());
        int length = Math.toIntExact(SmallSectionLength);
        if (requestResponse.getBitTotal() == 1 || i == requestResponse.getBitTotal() - 1) { //如果是最后一位,那么长度用 总长度-前面的长度即可
            length = Math.toIntExact(requestResponse.getSectionLength() - i * SmallSectionLength);
        }
        ByteBuf byteBuf =  FileUtil.readChannel(channel, uploadCommand.getBegin(), length);
        uploadCommand.setLength((long) byteBuf.capacity());
        uploadCommand.setByteBuf(byteBuf);
        if (i == requestResponse.getBitSize() - 1) {
            uploadCommand.setLast(true);
        }
        return uploadCommand;
    }
}
